using UnityEngine;
using System.Collections;


/*
 * Общее описание работы:
 * Наклон:
 * 	- Глобальный. Направление в котором движется листок в данной итерации раскачивания.
 * 	- Мгновенный. Наклон в данный момент времени.
 * Ориентация листка:
 * 	- Нормальная. Листок расположен прогибом вниз, острая часть направлена направо.
 * 	- Обратная. Листок расположен прогибом вверх, острая часть направлена налево.
 *  
 * 
 * */


public class LeafController : MonoBehaviour 
{
	//Параметры:
	//Основная сила, действующая на листок
	public float forwardForceCoof = 20f;
	public int ffcMin = 20;
	public int ffcMax = 30;	
	
	//Обратная сила, действующая на листок
	public float backwardForceCoof = 1.85f;	
	public float bfcPiece = 0.75f;
	
	//Сила, возвращающая листок в нормальную ориентацию
	public float returnForceCoof = 15f;
	public int rfcMin = 15;
	public int rfcMax = 20;	
	
	//Скорость закручивания листка в нормальной ориентации
	public float normalRotateCoof = 250f;
	public int nrcMin = 300;
	public int nrcMax = 400;
	
	//Скорость закручивания листка в обратной ориентации
	public float returnRotateCoof = 50f;
	public int rrcMin = 30;
	public int rrcMax = 50;


	private System.Random random;
	
	private float sin, cos; //Вспомогательные для вычисление угла и направления
	private float angle; //Угол между листом и горизонталью
	private float globalDir; //Направление, в котором движется листок
	private float localDir; //Направление, в котором расположен листок в данный момент
	
	//Угол наклона относитель горизонтальной оси. А также синус и косинус этого угла
	private void GetAngle(out float angle, out float sin, out float cos)
	{
		angle = Vector3.Angle(Vector3.right, gameObject.transform.right) * Mathf.Deg2Rad;
		if((Vector3.Cross(Vector3.right, gameObject.transform.right)).y > 0)
			angle = -angle;
		sin = Mathf.Sin(angle);
		cos = Mathf.Cos(angle);		
	}
	
	
	//Словное вычисление текущего направления листка.
	//Можно использовать просто значение угла. 
	//ИСПРАВИТЬ.
	private void GetDir(out float dir, out float angle, out float sin, out float cos)
	{		
		GetAngle(out angle, out sin, out cos);
		if(Mathf.Abs(cos*sin) < 0.0001)
		{
			dir = 0;
			return;
		}
		if(cos*sin > 0)
			dir = -1;
		else 
			dir = 1;
		//dir = 1 двигаемся вправо
		//dir = -1 двигаемся влево
		//Debug.Log("Angle: " + angle*Mathf.Rad2Deg + " Sin: " + sin + " Cos: " + cos + " Dir: " + dir);	
	}
	
	void Start() 
	{
		random = new System.Random();
		GetDir(out globalDir, out angle, out sin, out cos);
		RecalculateCoof();
		/*
		gameObject.transform.Translate(Random.value*10.0f, 0.0f, Random.value*10.0f);
		gameObject.transform.Rotate(0.0f, Random.value*360.0f, 0.0f);
		*/
	}
	
	
	void FixedUpdate() 
	{
		//Вычисляем мгновенную ориентацию листка
		GetDir(out localDir, out angle, out sin, out cos);
		//В зависимости от наклона листка меняем сопротивление воздуха
		gameObject.rigidbody.drag = Mathf.Abs(cos)*3.0f;
		
		//Если листок имеет прямую ориентацию (прогиб направлен внизб острая часть смотрит направо), то...
		if(Mathf.Abs(angle*Mathf.Rad2Deg) < 90)
		{
			//Добавляем основную силу, под воздействием которой листок будет двигаться
			gameObject.rigidbody.AddForce(gameObject.transform.right*globalDir*forwardForceCoof*Mathf.Abs(cos), ForceMode.Force);
			//Добавляем обратную силу (силу торможения)
			gameObject.rigidbody.AddForce(gameObject.transform.right*localDir*backwardForceCoof*Mathf.Abs(sin), ForceMode.Force);
			//Поворачиваем листок, имитируя его закручивание.
			//Мгновенный угол закручивания зависит от мгновенной скорости листка
			//НЕОБХОДИМО добавить ещё минимум два варианта расчет угла закручивания
			gameObject.transform.RotateAround(gameObject.rigidbody.centerOfMass, (-1)*globalDir*(Mathf.Abs(gameObject.rigidbody.velocity.magnitude)+Mathf.Abs(cos))*normalRotateCoof);			
			//Debug.Log((-1)*globalDir*(angle + 1.0f)*normalRotateCoof);					
		}
		//Если листок имеет обратную ориетнацию (см. выше), то...
		else
		{
			//Применяем к листку основную силу для его переворота в нормальную ориентацию
			gameObject.rigidbody.AddForce(gameObject.transform.right*returnForceCoof*Mathf.Abs(cos)*Mathf.Sign(localDir)*(-1), ForceMode.Force);
			//... и поворавичаем.
			gameObject.transform.RotateAround(gameObject.rigidbody.centerOfMass, localDir*returnRotateCoof*(Mathf.Abs(cos)+1.0f) + localDir*0.0f);	
			GetAngle(out angle, out sin, out cos);
			if(Mathf.Abs(angle*Mathf.Rad2Deg) < 90)
				GetDir(out globalDir, out angle, out sin, out cos);
		}
		
		//Если скорость листка упала ниже порога, то...
		if(Mathf.Abs(gameObject.rigidbody.velocity.x) < 0.2f)
		{
			//Пересчитываем заново глобальную ориентацию на следующее раскачивание
			GetDir(out globalDir, out angle, out sin, out cos);
			RecalculateCoof();
		}
		//Debug.Log(" ***V: " + leaf.velocity.magnitude + " ***Angle: " + angle*Mathf.Rad2Deg + " ***gDir: " + globalDir + " ***lDir: " + localDir);
				
	}
	
	void RecalculateCoof()
	{
		//Считаем скорость закручивания
		normalRotateCoof = 1.0f / random.Next(nrcMin, nrcMax);
		//Основную силу и...
		forwardForceCoof = random.Next(ffcMin, ffcMax) / 10.0f;
		//Обратную.
		backwardForceCoof = bfcPiece * forwardForceCoof;
		//Силу возвращения листка в нормальнуб ориентацию
		returnForceCoof = random.Next(rfcMin, rfcMax) / 10.0f;
		//Скорость обратного закручивания
		returnRotateCoof = 1.0f / random.Next(rrcMin, rrcMax);		
	}
}
